package com.william.jdbcplus.core.toolkit.lambda;

import com.william.jdbcplus.core.toolkit.lambda.support.TestEntity;
import com.william.jdbcplus.core.toolkit.PropertyNamerUtils;
import com.william.jdbcplus.core.toolkit.ReflectionKit;
import com.william.jdbcplus.core.toolkit.lambda.support.SFunction;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Locale;

/**
 * Lambda 解析工具类
 */
public final class LambdaUtils {

    private static <T> SerializedLambda resolve(SFunction<T, ?> func) {
        try {
            // 直接调用writeReplace
            Method writeReplace = func.getClass().getDeclaredMethod("writeReplace");
            writeReplace.setAccessible(true);
            SerializedLambda serializedLambda = (SerializedLambda) writeReplace.invoke(func);
            return serializedLambda;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private static String getFieldProperty(SerializedLambda lambda) {
        String getterName = lambda.getImplMethodName();
        if (getterName.startsWith("lambda$")) {
            throw new RuntimeException("lambda表达式必须是对象方法引用写法,格式如  对象名::非静态方法名 ");
        }
        Class<?> clazz = SerializedLambdaUtil.getImplClass(lambda);
        List<Field> fieldList = ReflectionKit.getFieldList(clazz);
        for (Field field : fieldList) {
            String name = field.getName();
            if (name.length() >= 1 && Character.isLowerCase(name.charAt(0))) {
                name = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1);
            }
            String isField = "is" + name;
            String getField = "get" + name;
            if (isField.equals(getterName) || getField.equals(getterName)) {
                return field.getName();
            }
        }

        return PropertyNamerUtils.methodToProperty(getterName);
    }

    public static <T> String getFieldProperty(SFunction<T, ?> func) {
        return LambdaUtils.getFieldProperty(LambdaUtils.resolve(func));
    }

    public static <T> Class<T> getFuncClass(SFunction<T, ?> func) {
        SerializedLambda lambda = LambdaUtils.resolve(func);
        Class<T> clazz = (Class<T>) SerializedLambdaUtil.getImplClass(lambda);
        return clazz;
    }

    public static void main(String[] args) {
        SFunction<TestEntity, ?> function = TestEntity::getAccount;
        SFunction<TestEntity, ?> function2 = TestEntity::getAccount;
        SFunction<TestEntity, ?> function3 = TestEntity::getAccount;
        SFunction<TestEntity, ?> function4 = e -> e.getAccount();
        System.out.println(function.getClass().getName());
        System.out.println(function2.getClass().getName());
        System.out.println(function3.getClass().getName());
        System.out.println(function4.getClass().getName());
        System.out.println(function.getClass().equals(function2.getClass()));

        long beginTime = System.currentTimeMillis();

        String field = null;
        for (int i = 0; i < 1; i++) {
             field = getFieldProperty(function);
        }

        System.out.println(field);

        long endTime = System.currentTimeMillis();

        String field2 = null;
        for (int i = 0; i < 1; i++) {
            field2 = getFieldProperty(function);
        }

        System.out.println(field2);

        long endTime2 = System.currentTimeMillis();

        // 3、消耗的时间
        long consumeTime = endTime - beginTime;
        System.out.println(String.format(" { consume %d msec}--------------------", consumeTime));

        long consumeTime2 = endTime2 - endTime;
        System.out.println(String.format(" { consume %d msec}--------------------", consumeTime2));
    }
}
